# pyqt+socket聊天室
import socket
from threading import Thread
import time


class Receiver():
    # 初始方法
    def __init__(self):
        # 创建套接字
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 本地ip和端口号
        self.local_addr = ("", 7788)
        # 绑定本地ip
        self.server_socket.bind(self.local_addr)
        self.server_socket.listen(128)
        # 所有的客户端
        self.clients = []
        # 用户的name和ip
        self.clients_name_ip = {}
        self.get_conn()
        # 监听客户端与服务器连接

    def get_host_ip(self):
        """
        查询本机ip地址
        :return: ip
        """
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(('8.8.8.8', 80))
            ip = s.getsockname()[0]
        finally:
            s.close()

        return ip

    def get_conn(self):
        while True:
            # 给客户端分配一个新的socket，获取客户端的ip地址
            new_socket, client_address = self.server_socket.accept()
            print(client_address)
            data = "与服务器连接成功，需要输入昵称才能通信!"
            # 套接字向客户端发送数据
            new_socket.send(data.encode())
            # 连接的所有用户添加到服务器的用户列表里面
            self.clients.append(new_socket)
            # 服务器启动多个线程，处理每一个客户端的消息
            Thread(target=self.get_msg, args=(new_socket, self.clients, self.clients_name_ip, client_address)).start()

        # 进行所有客户端消息的处理

    def get_msg(self, new_socket, clients, clients_name_ip, client_address):
        # 接受客户端发来的昵称
        name = new_socket.recv(1024).decode()
        print("from client" + name)
        # 将昵称和ip进行绑定
        clients_name_ip[client_address] = name
        # 循环监听所有客户端的消息
        while True:
            # 获取所有客户发送的消息
            try:
                recv_data = new_socket.recv(1024).decode()
            except Exception as e:
                self.close_socket(new_socket, client_address)
                break

            if recv_data.upper() == "Q":
                self.close_socket(new_socket, client_address)
                break
            for c in clients:
                c.send((clients_name_ip[client_address] + " " +
                        time.strftime("%x") + "\n" + recv_data).encode())

    # 关闭资源
    def close_socket(self, new_socket, client_address):
        self.clients.remove(new_socket)
        new_socket.close()
        print(self.clients_name_ip[client_address] + "已经离开")
        # 通知所有客户端，该客户已经离开
        for c in self.clients:
            c.send((self.clients_name_ip[client_address] + "已经离开了").encode())

if __name__ == '__main__':
    Receiver()
